home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 1.iso / toolbox / documents / Inventor / www / workarounds / PathPatch.2.0.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-11-11  |  4.9 KB  |  179 lines

  1. //
  2. // This is a patch for the Inventor 2.0 SoPath code.  Three routines
  3. // had bugs in them that affected some programs:
  4. // The getLength() would return incorrect results sometimes for nodes
  5. // with hidden children.
  6. // The containsPath() method could return incorrect results if both
  7. // paths contained hidden children
  8. // And the isRelevantNotification method could cause core dumps when
  9. // used with SoSF/MFPath fields.
  10. //
  11. //
  12. // To apply this patch, compile this file into a .o and then link
  13. // the .o before -lInventor.  The linker may give a warning.
  14. // This is normal and expected.
  15. //
  16.  
  17. #include <Inventor/SoPath.h>
  18. #include <Inventor/misc/SoChildList.h>
  19. #include <Inventor/misc/SoNotification.h>
  20. #include <Inventor/nodes/SoNode.h>
  21. #include <Inventor/nodes/SoGroup.h>
  22.  
  23. ////////////////////////////////////////////////////////////////////////
  24. //
  25. // Description:
  26. //    Returns the public length of the path.
  27. //
  28. // Use: public
  29.  
  30. int
  31. SoPath::getLength() const
  32. //
  33. ////////////////////////////////////////////////////////////////////////
  34. {
  35.     // Cast const away...
  36.     SoPath *This = (SoPath *)this;
  37.  
  38.     // If we aren't sure how many are public, figure it out:
  39.     if (numPublic == -1) {
  40.  
  41.     int lastPublicIndex = 0;
  42.     if (minNumPublic > 1)
  43.         lastPublicIndex = minNumPublic - 1;
  44.  
  45.     // Last test is for the second to last node.
  46.     // If it passes, then lastPublicIndex will be incremented to be the
  47.     // final node, which we don't need to test.
  48.  
  49.     for (  ; lastPublicIndex < (getFullLength() - 1) ; lastPublicIndex++) {
  50.         // Children of this node will be private, so stop.
  51.         if ( ! nodes[lastPublicIndex]->isOfType(SoGroup::getClassTypeId()))
  52.         break;
  53.     }
  54.     This->numPublic = This->minNumPublic = lastPublicIndex + 1;
  55.     }
  56.     return numPublic;
  57. }
  58.  
  59. ////////////////////////////////////////////////////////////////////////
  60. //
  61. // Description:
  62. //    Returns TRUE if the nodes in the chain in the passed path are
  63. //    contained (in consecutive order) in this path chain.
  64. //
  65. // Use: public
  66.  
  67. SbBool
  68. SoPath::containsPath(const SoPath *path) const
  69. //
  70. ////////////////////////////////////////////////////////////////////////
  71. {
  72.     int i, j;
  73.  
  74.     // First find the head of the target path in this path
  75.     for (i = 0; i < getFullLength(); i++)
  76.     if (getNode(i) == path->getHead())
  77.         break;
  78.  
  79.     // Head node is not there
  80.     if (i == getFullLength())
  81.     return FALSE;
  82.  
  83.     // If there aren't enough nodes left in this path, then no match
  84.     if (getFullLength() - i < path->getFullLength())
  85.     return FALSE;
  86.  
  87.     // Otherwise, start comparing nodes in the two paths to see if the
  88.     // paths match
  89.     for (j = 0; j < path->getFullLength(); j++)
  90.     if (path->getNode(j) != getNode(i + j))
  91.         return FALSE;
  92.  
  93.     return TRUE;
  94. }
  95.  
  96. ////////////////////////////////////////////////////////////////////////
  97. //
  98. // Description:
  99. //    Returns TRUE if the given notification list involves a change to
  100. //    a node that affects the path. It is assumed that the last (most
  101. //    recent) node in the list is the head node of the path.
  102. //
  103. // Use: internal
  104.  
  105. SbBool
  106. SoPath::isRelevantNotification(SoNotList *list) const
  107. //
  108. ////////////////////////////////////////////////////////////////////////
  109. {
  110.     // Trace down the notification list to find the first node (if
  111.     // any) that is not on the path. Stop when we reach the first
  112.     // (in time) record that was at a node in the graph.
  113.  
  114.     const SoNotRec    *rec = list->getLastRec();
  115.     const SoNotRec    *prevRec = NULL;
  116.     int            curIndex = 0;
  117.     SbBool        offPath  = FALSE;
  118.  
  119.     while (rec != NULL && curIndex < getLength()) {
  120.  
  121.     // Stop if the node in the current record is not the next node
  122.     // in the path
  123.     if (rec->getBase() != getNode(curIndex)) {
  124.         offPath = TRUE;
  125.         break;
  126.     }
  127.  
  128.     // Go to the next record and path node, IF we're following a
  129.     // PARENT notification
  130.     if (rec->getPrevious() != NULL &&
  131.         rec->getPrevious()->getType() != SoNotRec::PARENT) {
  132.         break;
  133.     }
  134.     prevRec = rec;
  135.     rec = rec->getPrevious();
  136.  
  137.     curIndex++;
  138.     }
  139.  
  140.     // If not all notified nodes are on the path, we have to do some
  141.     // extra testing
  142.     if (offPath) {
  143.  
  144.     const SoNode    *node;
  145.     int        index;
  146.  
  147.     // The "rec" record points to a node that is off the path.
  148.     // Find out the index of this node in the parent node, which
  149.     // is pointed to by the previous record (which is guaranteed
  150.     // to exist and be on the path).
  151.     node = (const SoNode *) rec->getBase();
  152.     index= ((const SoNode *)prevRec->getBase())->getChildren()->find(node);
  153.  
  154.     // If the node is to the right of the path, the change does
  155.     // not affect the path
  156.     if (index > getIndex(curIndex))
  157.         return FALSE;
  158.  
  159.     // If it is to the left, it doesn't affect the path if any of
  160.     // the notification records go through a separator-type object:
  161.     else {
  162.         while (TRUE) {
  163.         if (! node->affectsState())
  164.             return FALSE;
  165.  
  166.         rec = rec->getPrevious();
  167.         if (rec == NULL || rec->getType() != SoNotRec::PARENT)
  168.             break;
  169.  
  170.         node = (const SoNode *) rec->getBase();
  171.         }
  172.     }
  173.     }
  174.  
  175.     // If we made it this far, it's a relevant notification
  176.     return TRUE;
  177. }
  178.  
  179.